package cn.javabb.project.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.javabb.common.constant.ConsVal;
import cn.javabb.common.exception.DBException;
import cn.javabb.common.exception.GenException;
import cn.javabb.common.model.domain.AjaxResult;
import cn.javabb.framework.config.DataSourceConfig;
import cn.javabb.framework.model.GenConfig;
import cn.javabb.framework.model.GenModel;
import cn.javabb.framework.util.DBUtil;
import cn.javabb.project.entity.*;
import cn.javabb.project.util.GenUtil;
import cn.javabb.project.util.VelocityUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @desc:
 * @author: javabb (javabob(a)163.com)
 * @create: 2021/05/04 23:09
 */
@Slf4j
@Service
public class GenService {
    @Value("${gen.rootPath}")
    private String rootPath;

    @Autowired
    private SysDataSourceService sysDataSourceService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private GenTableService genTableService;
    @Autowired
    private GenTableColumnService genTableColumnService;
    @Autowired
    private TemplateService templateService;
    @Autowired
    private GenProjectService projectService;
    // 获取项目目录
    public String getProjectDir(){
        return rootPath + "project"+File.separator;
    }
    // 获取下载目录
    public String getDownloadDir() {
        return rootPath+"download"+File.separator;
    }

    public List<GenTable> listDbTableByDsId(Long dscId) throws SQLException {
        SysDataSource dataSource = sysDataSourceService.getById(dscId);
        List<GenTable> tables = new DBUtil(GenUtil.getDataSourceConfig(dataSource)).listTable(new ArrayList<>());
        return tables;
    }

    /**
     * 获取生成表信息
     */
    @Transactional
    public String getGenTables(GenConfig config) {
        if (CollUtil.isEmpty(config.getModels())) {
            throw new GenException("模块分类为空");
        }
        DataSourceConfig dsc = sysDataSourceService.getDscById(config.getDscId());

        // 每次都生成 projectId
        String projectId = IdUtil.simpleUUID();
        for (GenModel model : config.getModels()) {
            try {
                //获取表信息 已经有的属性  tableName,remark
                List<GenTable> tables = new DBUtil(dsc).listTable(model.getTables());
                // 解析表
                for (GenTable table : tables) {
                    table.setProjectId(projectId);
                    table.setTableId(IdUtil.simpleUUID());
                    table.setClassName(GenUtil.convertClassName(table.getTableName(), model.getPrefix()));
                    table.setModuleName(model.getModelName());
                    table.setBusinessName(GenUtil.getBusinessName(table.getTableName()));
                    if (genTableService.save(table)) {
                        List<GenTableColumn> tableColumns = new ArrayList<>();
                        try {
                            //保存列
                            tableColumns = new DBUtil(dsc).listTableColumn(table);
                            if (CollUtil.isNotEmpty(tableColumns)) {
                                genTableColumnService.saveBatch(tableColumns);
                            }
                        } catch (Exception e) {
                            throw new DBException("获取表字段信息失败", e);
                        }
                    }
                }
            } catch (Exception e) {
                throw new GenException("获取表信息失败", e);
            }
        }
        return projectId;
    }

    /**
     * 导入表和表字段数据
     */
    @Transactional
    public void importGenTable(List<GenModel> genModels, Long dscId) {
        SysConfig config = sysConfigService.getById(1L);
        SysDataSource dataSource = sysDataSourceService.getById(dscId);
        //if (CollUtil.isEmpty(genModels)) {
            List<String> tableNames = new ArrayList<>();
            try {
                //获取表信息 已经有的属性  tableName,remark
                List<GenTable> tables = new DBUtil(GenUtil.getDataSourceConfig(dataSource)).listTable(null);
                tableNames = tables.stream().map(t -> t.getTableName()).collect(Collectors.toList());
            } catch (Exception e) {
                throw new GenException("获取表信息失败", e);
            }
            List<String> tablePrefixs = Arrays.stream(config.getTablePrefix().split(",")).collect(Collectors.toList());
            genModels = GenUtil.getGenModule(tableNames, tablePrefixs);
        //}
        // 分模块导入table
        for (GenModel model : genModels) {
            List<GenTable> tables = new ArrayList<>();
            try {
                //获取表信息 已经有的属性  tableName,remark
                tables = new DBUtil(GenUtil.getDataSourceConfig(dataSource)).listTable(model.getTables());
            } catch (Exception e) {
                throw new GenException("获取表信息失败", e);
            }
            // 解析表
            for (GenTable table : tables) {

                table.setTableId(IdUtil.simpleUUID());
                table.setClassName(GenUtil.convertClassName(table.getTableName(), model.getPrefix()));
                table.setPackageName(StrUtil.isBlank(model.getModelName())?config.getPackageName():(config.getPackageName() + "." + model.getModelName()));
                table.setModuleName(model.getModelName());
                table.setBusinessName(GenUtil.getBusinessName(table.getTableName()));
                if (genTableService.save(table)) {
                    List<GenTableColumn> tableColumns = new ArrayList<>();
                    try {
                        //保存列
                        tableColumns = new DBUtil(GenUtil.getDataSourceConfig(dataSource)).listTableColumn(table);
                        genTableColumnService.saveBatch(tableColumns);
                    } catch (Exception e) {
                        throw new DBException("获取表信息失败", e);
                    }

                }
            }
        }
    }

    /**
     * 获取表和列信息
     * @param query
     * @return
     */
    public List<GenTable> getGenTables(GenTable query) {
        List<GenTable> list = genTableService.list(query);
        for (GenTable table : list) {
            List<GenTableColumn> tableColumns = genTableColumnService.listByTableId(table.getTableId());
            // 主鍵
            if (CollUtil.isNotEmpty(tableColumns)) {
                List<GenTableColumn> tempColumns = new ArrayList<>();
                //列的顺序以主键开头
                for (GenTableColumn c : tableColumns) {
                    if (c.isPk()) {
                        table.setPkColumn(c);
                        break;
                    }
                }
                if(table.getPkColumn() != null){
                    tempColumns.add(table.getPkColumn());
                    for (GenTableColumn c : tableColumns) {
                        if (!c.getColumnId().equals(table.getPkColumn().getColumnId())) {
                            tempColumns.add(c);
                        }
                    }
                    table.setColumns(tempColumns);
                }else{
                    table.setColumns(tableColumns);
                }
            }
        }
        return list;
    }

    /**
     * 生成代码
     * @throws IOException
     */
    public void genCode(GenConfig config) throws IOException {

        List<GenTable> genTables = getGenTables(GenTable.builder().projectId(config.getProjectId()).build());;
        List<SysTemplate> templates = templateService.listByGroupId(config.getTemplateId());
        if (CollUtil.isEmpty(genTables) || CollUtil.isEmpty(templates)) {
            throw new GenException("代码生成异常");
        }
        VelocityUtil.initVelocity();
        for (GenTable table : genTables) {
            for (SysTemplate template : templates) {
                StringWriter stringWriter = new StringWriter();
                VelocityContext context = VelocityUtil.prepareContext(table,template,config);
                Velocity.evaluate(context, stringWriter, "", template.getContent());
                //生成文件名   rootPath + packagePath
                String projectPath = getProjectDir() + config.getProjectId() + File.separator;
                String packagePath = config.getPackageName().replace(".", "/") + File.separator+table.getModuleName() +File.separator+ template.getPackageSuffix().replace(".","/")+File.separator;
                // {}.java
                String fileName = projectPath + packagePath + StrUtil.format(template.getFileName(), table.getClassName());
                FileUtils.writeStringToFile(new File(fileName), stringWriter.toString(), ConsVal.UTF8);
            }
        }
        //删除历史数据
        genTableService.deleteByProjectId(config.getProjectId());
    }

}
